#pragma once
#include <type_system/value_kind.hpp>
#include <string_view>
#include <string>
#include <vector>
#include <optional>

namespace blitz_query_cpp
{
    class value_node_t
    {
    public:
        value_kind kind;
        std::string name;
        std::string value;
        std::vector<value_node_t> children;
        std::string_view get_value() const { return value; }

        value_node_t &add_child_node(value_kind kind, std::string_view name = {}, std::string_view value = {})
        {
            if(kind == value_kind::String && !value.begin())
                return children.emplace_back(value_kind::Null, std::string{name});
            return children.emplace_back(kind, std::string{name}, std::string{value});
        }

        value_node_t &add_child_node_bool(value_kind kind, std::string_view name, bool value)
        {
            return add_child_node(kind, name, std::string_view{value ? "true" : "false"});
        }

        template <class WriterT>
        void serialize(WriterT &writer)
        {
            switch (kind)
            {
            case value_kind::Boolean:
            case value_kind::Float:
            case value_kind::Integer:
            {
                auto val = get_value();
                if (val.empty())
                {
                    writer.write_null(name);
                }
                else
                {
                    writer.write_literal_value(name, val);
                }
            }
            break;
            case value_kind::List:
                if (name.empty())
                    writer.begin_array();
                else
                    writer.begin_array(name);
                for (auto &&child : children)
                {
                    child.serialize(writer);
                }
                writer.end_array();
                break;
            case value_kind::Object:
                if (name.empty())
                    writer.begin_object();
                else
                    writer.begin_object(name);
                for (auto &&child : children)
                {
                    child.serialize(writer);
                }
                writer.end_object();
                break;
            case value_kind::Null:
                writer.write_null(name);
                break;
            case value_kind::Enum:
            case value_kind::String:
            {
                auto val = get_value();
                if (!val.begin())
                {
                    writer.write_null(name);
                }
                else
                {
                    writer.write_str_value(name, get_value());
                }
            }
            break;
            default:
                break;
            }
        }
    };
}
